
#ifndef _WIN32_WINNT
#define _WIN32_WINNT 0x400
#endif
#define WIN32_LEAN_AND_MEAN
#include <windows.h>

#include <scene/SceneManager.h>

#include <event/events.h>
#include <base/d3d.h>

//CRITICAL_SECTION cs_switch;
//CRITICAL_SECTION cs_buffer[2];
//unsigned long timestamp[2];
//unsigned long laststamp;
//
//SceneNode * write;
//SceneNode * read[2];

//test code:
//#include <string>
//#include <fstream>
//
//std::string chars;
//std::ofstream log;
//bool writechars = true;
//char last_char = 'x';

//class MemManager
//{
//public:
//  MemManager() {
//    InitializeCriticalSection(&cs_switch);
//    InitializeCriticalSection(&cs_buffer[0]);
//    InitializeCriticalSection(&cs_buffer[1]);
//    laststamp = 0;
//    write = NULL;
//    read[0] = NULL;
//    read[1] = NULL;
//    //log.open("log.txt");
//    //log<<"Starting log\n";
//  }
//  ~MemManager() {
//    DeleteCriticalSection(&cs_switch);
//    DeleteCriticalSection(&cs_buffer[0]);
//    DeleteCriticalSection(&cs_buffer[1]);
//    //if(write)
//      //delete write;
//    if(read[0])
//      read[0]->destroyGraph();
//    if(read[1])
//      read[1]->destroyGraph();
//
//    //log.close();
//  }
//};
//
//MemManager manager;

// 3 graphs, 1 to write in app, 2 to read

// main thread
//
// lock switch
// get ready graph (newest or open)
// lock ready graph
// switch to ready
// unlock switch
// render
// unlock ready 

// this should only be called in the main thread
long RenderGraph(Device * device) {
  unsigned long newest;
  unsigned long oldest;
  unsigned long buffer_used;

  EnterCriticalSection(&(device->cs_switch));
  if(device->timestamp[0] > device->timestamp[1]) {
    newest = 0;
    oldest = 1;
  } else {
    newest = 1;
    oldest = 0;
  }

  //log<<"rg: "<<newest<<"\n";

  buffer_used = newest;
  if(!TryEnterCriticalSection(&(device->cs_buffer[buffer_used]))) {
    buffer_used = oldest;
    if(!TryEnterCriticalSection(&(device->cs_buffer[buffer_used])))
      return -1; //wtf, both locked?
  }

  //log<<"    "<<buffer_used<<" "<<timestamp[buffer_used]<<"\n";

  //test code:
  //if(writechars) {
  //  if(chars.size() < 200) {
  //    chars.push_back(last_char);
  //    if(buffer_used == 0) {
  //      chars.push_back('0');
  //    } else {
  //      chars.push_back('1');
  //    }
  //  } else {
  //    writechars = false;
  //    events::Fire(new events::PrintConsole(chars));
  //  }
  //}
  long retval;
  LeaveCriticalSection(&(device->cs_switch));
  if(device->timestamp[buffer_used] != 0) { // a timestamp of 0 means this buffer isn't written
    if(device->read[buffer_used]){
      retval = device->read[buffer_used]->drawScene(device);
    }
  }
  LeaveCriticalSection(&(device->cs_buffer[buffer_used]));
  return retval;
}


// app thread - copy write to read
//
// lock switch
// get oldest or open
// lock ready graph
// unlock switch
// copy write to read
// unlock ready graph

// this should only be called in the app thread
long CopyGraph(SceneNode * scene, Device * device) {
  unsigned long newest;
  unsigned long oldest;
  unsigned long buffer_used;

  EnterCriticalSection(&(device->cs_switch));
    if(device->timestamp[0] > device->timestamp[1]) {
    newest = 0;
    oldest = 1;
  } else {
    newest = 1;
    oldest = 0;
  }

  //log<<"ng: "<<oldest<<"\n";

  buffer_used = oldest;
  if(!TryEnterCriticalSection(&(device->cs_buffer[buffer_used]))) {
    buffer_used = newest;
    if(!TryEnterCriticalSection(&(device->cs_buffer[buffer_used])))
      return -1; //wtf, both locked?
  }

  //log<<"    "<<buffer_used<<"\n";

  //test code:
  //if(writechars) {
  //  if(chars.size() < 100) {
  //    if(buffer_used == 0) {
  //      last_char = 'a';
  //    } else {
  //      last_char = 'b';
  //    }
  //  } else {
  //    writechars = false;
  //    events::Fire(new events::PrintConsole(chars));
  //  }
  //}

  device->timestamp[buffer_used] = ++(device->laststamp);
  //timestamp wrap-around
  if(device->laststamp == 0xffffffff) {
    device->timestamp[buffer_used] = 2;
    device->timestamp[buffer_used ? 0 : 1] = 1;
    device->laststamp = 2;
  }
  LeaveCriticalSection(&(device->cs_switch));
  if(device->read[buffer_used])
    device->read[buffer_used]->destroyGraph();
  device->read[buffer_used] = scene->copyGraph();
  LeaveCriticalSection(&(device->cs_buffer[buffer_used]));

  return 0;
}
